package service

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"reflect"
	"strconv"
	"time"

	"github.com/ammyhaber/seckill/pkg/breaker"
	"github.com/ammyhaber/seckill/service/inventory/model"
	"github.com/ammyhaber/seckill/service/order/middleware"
)

// 商品信息
type ProductInfo struct {
	ID    int64   `json:"id"`
	Name  string  `json:"product_name"`
	Price float64 `json:"product_price"`
}

// 库存服务响应
type InventoryResponse struct {
	Code int             `json:"code"`
	Msg  string          `json:"msg"`
	Data json.RawMessage `json:"data,omitempty"`
}

// 获取商品信息
func (s *OrderService) getProductInfo(ctx context.Context, productID int64) (*ProductInfo, error) {
	// 如果有内部库存服务（测试模式），直接调用
	if s.inventoryService != nil {
		// 输出调试信息
		fmt.Printf("使用内部库存服务: %T\n", s.inventoryService)

		// 尝试使用更通用的方式获取GetInventoryDetail方法
		if invService, ok := s.inventoryService.(interface {
			GetInventoryDetail(context.Context, int64) (*model.InventoryDetail, error)
		}); ok {
			fmt.Println("成功获取GetInventoryDetail方法")
			detail, err := invService.GetInventoryDetail(ctx, productID)
			if err != nil {
				return nil, fmt.Errorf("获取库存详情失败: %w", err)
			}

			// 返回商品信息
			return &ProductInfo{
				ID:    detail.ProductID,
				Name:  detail.ProductName,
				Price: detail.ProductPrice,
			}, nil
		} else {
			// 尝试使用反射获取方法
			fmt.Println("类型断言失败，尝试使用结构体字段方式")

			// 检查是否有GetInventoryDetail字段
			v := reflect.ValueOf(s.inventoryService)
			if v.Kind() == reflect.Ptr {
				v = v.Elem()
			}

			// 如果是结构体类型
			if v.Kind() == reflect.Struct {
				// 寻找GetInventoryDetail方法
				method := v.FieldByName("GetInventoryDetail")
				if method.IsValid() && !method.IsNil() {
					// 可以调用该方法
					fmt.Println("找到GetInventoryDetail字段")
					// 尝试调用方法
					results := method.Call([]reflect.Value{
						reflect.ValueOf(ctx),
						reflect.ValueOf(productID),
					})

					// 检查返回值
					if len(results) == 2 {
						var detail *model.InventoryDetail
						var err error

						if !results[0].IsNil() {
							detail = results[0].Interface().(*model.InventoryDetail)
						}

						if !results[1].IsNil() {
							err = results[1].Interface().(error)
						}

						if err != nil {
							return nil, fmt.Errorf("获取库存详情失败: %w", err)
						}

						return &ProductInfo{
							ID:    detail.ProductID,
							Name:  detail.ProductName,
							Price: detail.ProductPrice,
						}, nil
					}
				}
			}
		}
	}

	// 正常模式：通过HTTP API调用
	if s.inventoryAPI == "" {
		return nil, errors.New("未配置库存服务地址")
	}

	// 构建请求URL
	url := fmt.Sprintf("%s/inventory?product_id=%d", s.inventoryAPI, productID)

	// 发送HTTP请求
	resp, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf("调用库存服务失败: %w", err)
	}
	defer resp.Body.Close()

	// 读取响应内容
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %w", err)
	}

	// 解析响应
	var response InventoryResponse
	if err := json.Unmarshal(body, &response); err != nil {
		return nil, fmt.Errorf("解析响应失败: %w", err)
	}

	// 检查响应状态
	if response.Code != 0 {
		return nil, errors.New(response.Msg)
	}

	// 解析商品信息
	var detail model.InventoryDetail
	if err := json.Unmarshal(response.Data, &detail); err != nil {
		return nil, fmt.Errorf("解析商品信息失败: %w", err)
	}

	// 返回商品信息
	return &ProductInfo{
		ID:    detail.ProductID,
		Name:  detail.ProductName,
		Price: detail.ProductPrice,
	}, nil
}

// 扣减库存
func (s *OrderService) decrInventory(ctx context.Context, productID int64, count int) (bool, error) {
	// 如果有内部库存服务（测试模式），直接调用
	if s.inventoryService != nil {
		// 输出调试信息
		fmt.Printf("使用内部库存服务decrInventory: %T\n", s.inventoryService)

		// 尝试使用类型断言获取库存服务方法
		if invService, ok := s.inventoryService.(interface {
			DecrInventory(context.Context, int64, int) (bool, error)
		}); ok {
			fmt.Println("成功获取DecrInventory方法")
			return invService.DecrInventory(ctx, productID, count)
		} else {
			// 尝试使用反射获取方法
			fmt.Println("DecrInventory类型断言失败，尝试使用结构体字段方式")

			// 检查是否有DecrInventory字段
			v := reflect.ValueOf(s.inventoryService)
			if v.Kind() == reflect.Ptr {
				v = v.Elem()
			}

			// 如果是结构体类型
			if v.Kind() == reflect.Struct {
				// 寻找DecrInventory方法
				method := v.FieldByName("DecrInventory")
				if method.IsValid() && !method.IsNil() {
					// 可以调用该方法
					fmt.Println("找到DecrInventory字段")
					// 尝试调用方法
					results := method.Call([]reflect.Value{
						reflect.ValueOf(ctx),
						reflect.ValueOf(productID),
						reflect.ValueOf(count),
					})

					// 检查返回值
					if len(results) == 2 {
						var success bool
						var err error

						success = results[0].Bool()

						if !results[1].IsNil() {
							err = results[1].Interface().(error)
						}

						if err != nil {
							return false, err
						}

						return success, nil
					}
				}
			}
		}
	}

	// 正常模式：通过HTTP API调用
	if s.inventoryAPI == "" {
		return false, errors.New("未配置库存服务地址")
	}

	// 获取库存服务熔断器
	inventoryBreaker := middleware.GetBreakerManager().GetBreaker("inventoryService")

	// 使用熔断器包装HTTP调用
	result, err := inventoryBreaker.ExecuteWithResult("decrInventory", func() (interface{}, error) {
		// 构建请求URL
		url := fmt.Sprintf("%s/inventory/decr", s.inventoryAPI)

		// 构建请求体
		reqBody, err := json.Marshal(map[string]interface{}{
			"product_id": productID,
			"count":      count,
		})
		if err != nil {
			return false, fmt.Errorf("构建请求失败: %w", err)
		}

		// 发送HTTP请求
		resp, err := http.Post(url, "application/json", bytes.NewBuffer(reqBody))
		if err != nil {
			return false, fmt.Errorf("调用库存服务失败: %w", err)
		}
		defer resp.Body.Close()

		// 读取响应内容
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return false, fmt.Errorf("读取响应失败: %w", err)
		}

		// 解析响应
		var response InventoryResponse
		if err := json.Unmarshal(body, &response); err != nil {
			return false, fmt.Errorf("解析响应失败: %w", err)
		}

		// 检查响应状态
		if response.Code != 0 {
			return false, errors.New(response.Msg)
		}

		return true, nil
	})

	// 处理熔断器结果
	if err != nil {
		// 如果是服务降级错误，可以返回默认值或者自定义降级策略
		if errors.Is(err, breaker.ErrFallback) || errors.Is(err, breaker.ErrCircuitOpen) {
			return false, errors.New("库存服务暂时不可用，请稍后再试")
		}
		return false, err
	}

	// 类型断言
	success, ok := result.(bool)
	if !ok {
		return false, errors.New("返回结果类型错误")
	}

	return success, nil
}

// 确认库存扣减
func (s *OrderService) confirmInventoryDeduction(ctx context.Context, productID int64, count int) error {
	// 如果有内部库存服务（测试模式），直接调用
	if s.inventoryService != nil {
		// 输出调试信息
		fmt.Printf("使用内部库存服务confirmInventoryDeduction: %T\n", s.inventoryService)

		// 尝试使用类型断言获取库存服务方法
		if invService, ok := s.inventoryService.(interface {
			ConfirmDeduction(context.Context, int64, int) error
		}); ok {
			fmt.Println("成功获取ConfirmDeduction方法")
			return invService.ConfirmDeduction(ctx, productID, count)
		} else {
			// 尝试使用反射获取方法
			fmt.Println("ConfirmDeduction类型断言失败，尝试使用结构体字段方式")

			// 检查是否有ConfirmDeduction字段
			v := reflect.ValueOf(s.inventoryService)
			if v.Kind() == reflect.Ptr {
				v = v.Elem()
			}

			// 如果是结构体类型
			if v.Kind() == reflect.Struct {
				// 寻找ConfirmDeduction方法
				method := v.FieldByName("ConfirmDeduction")
				if method.IsValid() && !method.IsNil() {
					// 可以调用该方法
					fmt.Println("找到ConfirmDeduction字段")
					// 尝试调用方法
					results := method.Call([]reflect.Value{
						reflect.ValueOf(ctx),
						reflect.ValueOf(productID),
						reflect.ValueOf(count),
					})

					// 检查返回值
					if len(results) == 1 {
						var err error
						if !results[0].IsNil() {
							err = results[0].Interface().(error)
						}
						return err
					}
				}
			}
		}
	}

	// 正常模式：通过HTTP API调用
	if s.inventoryAPI == "" {
		return errors.New("未配置库存服务地址")
	}

	// 获取库存服务熔断器
	inventoryBreaker := middleware.GetBreakerManager().GetBreaker("inventoryService")

	// 使用熔断器包装HTTP调用
	_, err := inventoryBreaker.ExecuteWithResult("confirmInventory", func() (interface{}, error) {
		// 构建请求URL
		url := fmt.Sprintf("%s/inventory/confirm", s.inventoryAPI)

		// 构建请求体
		reqBody, err := json.Marshal(map[string]interface{}{
			"product_id": productID,
			"count":      count,
		})
		if err != nil {
			return nil, fmt.Errorf("构建请求失败: %w", err)
		}

		// 发送HTTP请求
		resp, err := http.Post(url, "application/json", bytes.NewBuffer(reqBody))
		if err != nil {
			return nil, fmt.Errorf("调用库存服务失败: %w", err)
		}
		defer resp.Body.Close()

		// 读取响应内容
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, fmt.Errorf("读取响应失败: %w", err)
		}

		// 解析响应
		var response InventoryResponse
		if err := json.Unmarshal(body, &response); err != nil {
			return nil, fmt.Errorf("解析响应失败: %w", err)
		}

		// 检查响应状态
		if response.Code != 0 {
			return nil, errors.New(response.Msg)
		}

		return nil, nil
	})

	// 处理熔断器结果
	if err != nil {
		// 如果是服务降级错误，记录日志但不阻止订单流程
		if errors.Is(err, breaker.ErrFallback) || errors.Is(err, breaker.ErrCircuitOpen) {
			return fmt.Errorf("库存确认服务暂时不可用，将稍后重试: %w", err)
		}
		return err
	}

	return nil
}

// 取消库存扣减
func (s *OrderService) cancelInventoryDeduction(ctx context.Context, productID int64, count int) error {
	// 如果有内部库存服务（测试模式），直接调用
	if s.inventoryService != nil {
		// 输出调试信息
		fmt.Printf("使用内部库存服务cancelInventoryDeduction: %T\n", s.inventoryService)

		// 尝试使用类型断言获取库存服务方法
		if invService, ok := s.inventoryService.(interface {
			CancelDeduction(context.Context, int64, int) error
		}); ok {
			fmt.Println("成功获取CancelDeduction方法")
			return invService.CancelDeduction(ctx, productID, count)
		} else {
			// 尝试使用反射获取方法
			fmt.Println("CancelDeduction类型断言失败，尝试使用结构体字段方式")

			// 检查是否有CancelDeduction字段
			v := reflect.ValueOf(s.inventoryService)
			if v.Kind() == reflect.Ptr {
				v = v.Elem()
			}

			// 如果是结构体类型
			if v.Kind() == reflect.Struct {
				// 寻找CancelDeduction方法
				method := v.FieldByName("CancelDeduction")
				if method.IsValid() && !method.IsNil() {
					// 可以调用该方法
					fmt.Println("找到CancelDeduction字段")
					// 尝试调用方法
					results := method.Call([]reflect.Value{
						reflect.ValueOf(ctx),
						reflect.ValueOf(productID),
						reflect.ValueOf(count),
					})

					// 检查返回值
					if len(results) == 1 {
						var err error
						if !results[0].IsNil() {
							err = results[0].Interface().(error)
						}
						return err
					}
				}
			}
		}
	}

	// 正常模式：通过HTTP API调用
	if s.inventoryAPI == "" {
		return errors.New("未配置库存服务地址")
	}

	// 获取库存服务熔断器
	inventoryBreaker := middleware.GetBreakerManager().GetBreaker("inventoryService")

	// 使用熔断器包装HTTP调用
	_, err := inventoryBreaker.ExecuteWithResult("cancelInventory", func() (interface{}, error) {
		// 构建请求URL
		url := fmt.Sprintf("%s/inventory/cancel", s.inventoryAPI)

		// 构建请求体
		reqBody, err := json.Marshal(map[string]interface{}{
			"product_id": productID,
			"count":      count,
		})
		if err != nil {
			return nil, fmt.Errorf("构建请求失败: %w", err)
		}

		// 发送HTTP请求
		resp, err := http.Post(url, "application/json", bytes.NewBuffer(reqBody))
		if err != nil {
			return nil, fmt.Errorf("调用库存服务失败: %w", err)
		}
		defer resp.Body.Close()

		// 读取响应内容
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, fmt.Errorf("读取响应失败: %w", err)
		}

		// 解析响应
		var response InventoryResponse
		if err := json.Unmarshal(body, &response); err != nil {
			return nil, fmt.Errorf("解析响应失败: %w", err)
		}

		// 检查响应状态
		if response.Code != 0 {
			return nil, errors.New(response.Msg)
		}

		return nil, nil
	})

	// 处理熔断器结果
	if err != nil {
		// 如果是服务降级错误，可以记录日志但不阻止订单流程
		if errors.Is(err, breaker.ErrFallback) || errors.Is(err, breaker.ErrCircuitOpen) {
			return fmt.Errorf("库存取消服务暂时不可用，将稍后重试: %w", err)
		}
		return err
	}

	return nil
}

// 生成订单ID
func (s *OrderService) generateOrderID(userID int64) int64 {
	// 简单实现，实际项目中应使用雪花算法或其他全局唯一ID生成方式
	timestamp := time.Now().UnixNano() / 1e6 // 毫秒时间戳
	random := rand.Intn(1000)                // 随机数
	userSuffix := userID % 1000              // 用户ID后缀

	// 组合生成订单ID
	orderIDStr := fmt.Sprintf("%d%03d%03d", timestamp, random, userSuffix)
	orderID, _ := strconv.ParseInt(orderIDStr, 10, 64)

	return orderID
}
